#include <QXmlInputSource>
#include <QXmlSimpleReader>

#include "cfg.h"

typedef struct {
	const char *name;
	int level;
} xmlCfgElement_t;

static const xmlCfgElement_t xmlCfgElement[] = {
	{"", 0},
	{"case", 1},

	{"info", 2},
	{"name", 3},
	{"author", 3},
	{"mail", 3},
	{"www", 3},
	{"desc", 3},

	{"width", 2},
	{"height", 2},

	{"bottom", 2},
	{"cover", 2},
	{"top", 2},
	{"merged", 2},
	{"rotation", 3},

	{"text", 2},
};

enum xmlCfgElementId {xceiRoot=0, xceiCase, xceiInfo, xceiName, xceiAuthor, xceiMail,
	xceiWWW, xceiDesc, xceiWidth, xceiHeight, xceiBottom, xceiCover, xceiTop,
	xceiMerged, xceiRotation, xceiText};

// inherited from QXmlDefaultHandler
bool Cfg::characters(const QString &ch)
{
	//printf("ch el: %s, ch: %s\n", xmlCfgElement[m_id].name, ch.toAscii().constData());

	switch (m_id) {
		case xceiName: m_info.name = ch; break;
		case xceiAuthor: m_info.author = ch; break;
		case xceiMail: m_info.mail = ch; break;
		case xceiWWW: m_info.www = ch; break;
		case xceiDesc: m_info.desc = ch; break;
		case xceiWidth: m_width = ch.toInt(); break;
		case xceiHeight: m_height = ch.toInt(); break;
		case xceiRotation: m_merged.rotation.angle = ch.toInt(); break;
		case xceiText: m_text.text = ch; break;
	}

	return true;
}

bool Cfg::endElement(const QString &/*namespaceURI*/, const QString &localName, const QString &/*qName*/)
{
	//printf("end el: %s\n", localName.toAscii().constData());
	if (xmlCfgElement[m_id].name != localName) return false;

	m_id = findParentElementId();
	//printf("level: %d, m_level: %d\n", level, m_level);
	if (m_id == -1) return false;

	return true;
}

bool Cfg::startDocument()
{
	m_id = 0;

	return true;
}

bool Cfg::startElement(const QString &/*namespaceURI*/, const QString &localName, const QString &/*qName*/, const QXmlAttributes &atts)
{
	//printf("el: %s\n", localName.toAscii().constData());
	int w, h;

	m_id = findChildElementId(localName);
	if (m_id == -1) return false;

	switch (m_id) {
		case xceiBottom:
			if (!m_bottom.pix.load(m_path + "bottom.png")) return false;
			if (m_bottom.pix.isNull()) return false;
			m_bottom.pt.setX(atts.value("", "x").toInt());
			m_bottom.pt.setY(atts.value("", "y").toInt());
			w = atts.value("", "w").toInt();
			h = atts.value("", "h").toInt();
			if (w && h) m_bottom.pix = m_bottom.pix.scaled(w, h);
			break;
		case xceiCover:
			if (!m_cover.no_cover_pix.load(m_path + "nocover.png")) return false;
			if (m_cover.no_cover_pix.isNull()) return false;
			w = atts.value("", "w").toInt();
			h = atts.value("", "h").toInt();
			m_cover.rect.setRect(atts.value("", "x").toInt(),
								 atts.value("", "y").toInt(),
								 w, h);
			if (w && h) m_cover.no_cover_pix = m_cover.no_cover_pix.scaled(w, h);
			break;
		case xceiTop:
			if (!m_top.pix.load(m_path + "top.png")) return false;
			if (m_top.pix.isNull()) return false;
			m_top.pt.setX(atts.value("", "x").toInt());
			m_top.pt.setY(atts.value("", "y").toInt());
			w = atts.value("", "w").toInt();
			h = atts.value("", "h").toInt();
			if (w && h) m_top.pix = m_top.pix.scaled(w, h);
			break;
		case xceiMerged:
			m_merged.rect.setRect(atts.value("", "x").toInt(),
								  atts.value("", "y").toInt(),
								  atts.value("", "w").toInt(),
								  atts.value("", "h").toInt());
			break;
		case xceiRotation:
			m_merged.rotation.pt.setX(atts.value("", "x").toInt());
			m_merged.rotation.pt.setY(atts.value("", "y").toInt());
			break;
		case xceiText:
			m_text.rect.setRect(atts.value("", "x").toInt(),
								atts.value("", "y").toInt(),
								atts.value("", "w").toInt(),
								atts.value("", "h").toInt());
			break;
		default: ;
	}

	return true;
}

// -- handler's helpers ---

int Cfg::findChildElementId(const QString &localName)
{
	int levelDelta = xmlCfgElement[m_id].level + 1;

	for (int id=m_id; id<(int) sizeof(xmlCfgElement); id++) {
		if (xmlCfgElement[id].level != levelDelta) continue;
		if (localName == xmlCfgElement[id].name) return id;
	}

	return -1;
}

int Cfg::findParentElementId()
{
	int levelDelta = xmlCfgElement[m_id].level - 1;
	int id = m_id;

	for ( ; -1<id; id--) {
		if (xmlCfgElement[id].level == levelDelta) break;
	}

	return id;
}

// --- rest of class ---

void Cfg::clear()
{
	m_info.name.clear();
	m_info.author.clear();
	m_info.mail.clear();
	m_info.www.clear();
	m_info.desc.clear();

	m_bottom.isValid = false;
	m_bottom.pt = QPoint(0, 0);
	m_bottom.pix = NULL;

	m_cover.isValid = false;
	m_cover.rect.setRect(0, 0, 0, 0);

	m_top.isValid = false;
	m_top.pt = QPoint(0, 0);
	m_top.pix = NULL;

	m_merged.isValid = false;
	m_merged.rect.setRect(0, 0, 0, 0);
	m_merged.rotation.angle = 0;
	m_merged.rotation.pt = QPoint(0, 0);

	m_text.text.clear();
	m_text.rect.setRect(0, 0, 0, 0);
}

void Cfg::load(const QString &path)
{
	clear();

	m_path = path;

	QFile file(m_path + "skin.xml");
	if (!file.exists()) return;

	QXmlInputSource xml_source(&file);

	QXmlSimpleReader xml_reader;
	xml_reader.setContentHandler(this);
	xml_reader.setErrorHandler(this);
	if (!xml_reader.parse(&xml_source)) return;

	if (!m_text.rect.width()) m_text.rect.setWidth(m_width - m_text.rect.x());
	if (!m_text.rect.height()) m_text.rect.setHeight(m_height - m_text.rect.y());
}
